import os.path
from typing import Literal, Tuple, Optional, List, Dict
import re
from jinja2 import Template


def exec_md_table(table_content: str) -> list:
    """
    处理md中的表格
    :param table_content: 含表格的文本
    :return: 取出的表格
    """
    table_content_list = table_content.split('\n')
    table = []
    for msg_frame_line in table_content_list:
        if len(msg_frame_line) > 0 and msg_frame_line[0] == '|':  # 取出表格
            field_list = msg_frame_line.replace(' ', '').split('|')
            if len(field_list) > 2:
                table.append(field_list[1:-1])
    return table


def exec_md_protocol(md_name: str) -> Optional[Tuple[List, List, Dict]]:
    with open(md_name, mode='r', encoding='utf-8') as fp:
        protocol_content = fp.read()
    # 将md拆解成消息结构、消息类型表、消息体定义，三部分
    protocol_content = protocol_content.replace('<br />', '；')
    if len(protocol_content) > 0:
        msg_frame_idx = protocol_content.find('## 1 消息结构')
        msg_type_idx = protocol_content.find('## 2 消息类型表')
        msg_body_idx = protocol_content.find('## 3 公共消息体定义')
        # 解析消息结构
        msg_frame_content = protocol_content[msg_frame_idx: msg_type_idx]
        _msg_frame_table = exec_md_table(msg_frame_content)[2:]  # 去除表头
        msg_type_content = protocol_content[msg_type_idx: msg_body_idx]
        _msg_type_table = exec_md_table(msg_type_content)[2:]  # 去除表头
        for cell in _msg_type_table:
            idx = cell[0].find(']')
            cell[0] = cell[0][1:idx]
        msg_body_content = protocol_content[msg_body_idx:]
        _msg_body_dict = {}
        for msg_body_cell in re.split(r'### \d+\.\d+ ', msg_body_content)[1:]:
            msg_body_title = msg_body_cell.split('\n')[0]
            msg_body_cell_table = exec_md_table(msg_body_cell)[2:]  # 去除表头
            _msg_body_dict[msg_body_title] = msg_body_cell_table
        print(_msg_frame_table)
        print(_msg_type_table)
        print(_msg_body_dict)
        return _msg_frame_table, _msg_type_table, _msg_body_dict
    return None


def make_out_file(jinja2_name: str, out_file: str, args: dict):
    with open(jinja2_name, mode='r', encoding='utf-8') as fp:
        string = fp.read()
    template = Template(string)
    out_str = template.render(args)
    with open(out_file, mode='w', encoding='utf-8') as fp:
        fp.write(out_str + '\n')


def get_c_expression(filed: list):
    filed_name = filed[0]
    filed_desc = filed[1]
    filed_type = filed[2]
    filed_len  = filed[3]
    filed_comm = filed[4]
    len_str = ''
    try:
        length_int = int(filed_len)
        if filed_type == 'BYTES':
            type_str = 'unsigned char '
            len_str = f'长度：{length_int} '
        elif filed_type == 'WORD':
            type_str = 'unsigned short'
        elif filed_type == 'BYTE':
            type_str = 'unsigned char '
        elif filed_type == 'DWORD':
            type_str = 'unsigned int  '
        else:
            type_str = '未知'
    except:
        type_str = 'void*         '
    return f'{type_str} {filed_name};  ///< {filed_desc} {len_str}{filed_comm}'


def get_msg_head_len(_msg_frame_table):
    len = 0
    for msg_cell in _msg_frame_table:
        if msg_cell[0] != 'MsgBody' and msg_cell[0] != 'MsgBodyLen':
            if msg_cell[2] == 'BYTE':
                len += 1
            elif msg_cell[2] == 'WORD':
                len += 2
            elif msg_cell[2] == 'DWORD':
                len += 4
    return len


if __name__ == "__main__":
    # 解析md
    msg_frame_table, msg_type_table, msg_body_dict = exec_md_protocol('网络通讯协议.md')
    # 生成代码
    if not os.path.exists('out'):
        os.mkdir('out')
    if not os.path.exists('out\\c'):
        os.mkdir('out\\c')
    if not os.path.exists('out\\python'):
        os.mkdir('out\\python')

    # C
    # c_arg = {
    #     '消息结构表': msg_frame_table,
    #     '消息类型表': msg_type_table,
    #     '消息体字典': msg_body_dict,
    #     '获取表达式': get_c_expression,
    #     'len': len,
    # }
    # make_out_file('j2\\c_h.j2', 'out\\c\\tsp.h', c_arg)

    # python
    py_arg = {
        '消息结构表': msg_frame_table,
        '消息类型表': msg_type_table,
        '消息体字典': msg_body_dict,
        'len': len,
        '获取消息头长度': get_msg_head_len,
    }
    make_out_file('j2\\py.j2', 'out\\python\\net_protocol.py', py_arg)
